package com.tbit.uqbike.tergateway.service.mqtt;

import com.tbit.uqbike.TerGatewayMain;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.protocol.AnalyzeImpl.AProtocol;
import com.tbit.uqbike.protocol.AnalyzeImpl.AutoProtocolImpl;
import com.tbit.uqbike.protocol.AnalyzeImpl.WA206DeEnCoder;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.TerTempData;
import com.tbit.uqbike.tergateway.wa206pkg.WA206Head;
import com.tbit.uqbike.util.ByteUtil;
import com.tbit.uqbike.util.ProtocolUtil;
import com.tbit.uqbike.util.StringUtil;
import com.tbit.uqbike.util.TbitTEAUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;

import java.util.Arrays;
import java.util.List;

public class DefMqttService {

    private static org.slf4j.Logger logger = LoggerFactory.getLogger(DefMqttService.class);

    public void messageRecv(Message<byte[]> msg) {
        // 只处理aaaa开头且长度大于12的报文
        byte[] pkgBytes = msg.getPayload();
        logger.info(String.format("mqtt:%s", ByteUtil.BytesToHexString(pkgBytes)));
        if (pkgBytes.length < 17 || (pkgBytes[0] & 0xff) != 0xaa || (pkgBytes[1] & 0xff) != 0xaa) {
            return;
        }
        AProtocol protocol = AutoProtocolImpl.getProtocol(WA206DeEnCoder.protocolName);
        if (null == protocol) {
            return;
        }
        // 为了解析出tid做一个临时变量
        byte[] tidPkg = null;
        // 如果是密文先尝试解密
        if (((pkgBytes[4] & 0xff) % 2) != 0) {
            // 取出密文报体
            byte[] bodyPkg = Arrays.copyOfRange(pkgBytes, WA206Head.HeadLen, pkgBytes.length - 2);
            // 解密报体
            bodyPkg = TbitTEAUtil.decrypt(bodyPkg, TbitTEAUtil.KEY);
            if (bodyPkg != null) {
                // 构造明文完整报文
                byte[] pkgs = new byte[WA206Head.HeadLen + bodyPkg.length + 2];
                System.arraycopy(pkgBytes, 0, pkgs, 0, WA206Head.HeadLen);
                // 重新设置长度，设置明文模式
                pkgs[2] = (byte) ((pkgs.length & 0xffff) >> 8);
                pkgs[3] = (byte) ((pkgs.length & 0xffff) >> 0);
                pkgs[4] = (byte) (pkgs[4] & 0xfe);
                System.arraycopy(bodyPkg, 0, pkgs, WA206Head.HeadLen, bodyPkg.length);
                // 重新计算校验和
                short crc = ProtocolUtil.GetCrcByteArray(pkgs, 2, pkgs.length - 4);
                pkgs[pkgs.length - 2] = (byte) ((crc & 0xffff) >> 8);
                pkgs[pkgs.length - 1] = (byte) ((crc & 0xffff) >> 0);
                tidPkg = pkgs;
            } else {
                logger.error("解密失败");
                return;
            }
        } else {
            tidPkg = pkgBytes;
        }
        // 取到设备编号生成设备唯一的mqtt连接对象
        String mno = StringUtil.TrimEnd(ByteUtil.BytesToHexString(tidPkg, 10, 8), 'F');
        String connId = String.format("mqtt.%s", mno);
        AConnInfo connInfo = TerGatewayData.CheckMqttConnect(connId);
        if (null == connInfo) {
            return;
        }
        // 绑定协议
        connInfo.proName = protocol.getProtocolName();
        connInfo.mno = mno;
        // 封装成ByteBuf走协议解析和处理流程
        ByteBuf in = null;
        try {
            in = PooledByteBufAllocator.DEFAULT.directBuffer();
            in.writeBytes(pkgBytes);
            handlePkg(connInfo, protocol, in);
        } finally {
            if (null != in) {
                in.release();
                in = null;
            }
        }
    }

    private static void handlePkg(AConnInfo connInfo, AProtocol protocol, ByteBuf in) {
        // 拿到协议对象，继续数据包拆分
        List<ATerPkg> pkgList = protocol.analyzeTerPkg(connInfo, in);
        String mno = connInfo.mno;
        if (StringUtil.IsNullOrEmpty(mno)) {
            mno = getMno(pkgList);
        }
        // 如果设备编号为空
        if (StringUtil.IsNullOrEmpty(mno)) {
            if (!pkgList.isEmpty()) {
                StringBuilder sb = new StringBuilder();
                for (ATerPkg pkg : pkgList) {
                    sb.append(pkg.toString());
                    sb.append(",");
                }
                logger.info(String.format("收到%d条未知设备编号的报文:%s", pkgList.size(), sb.toString()));
            }
        } else {
            byte version = 0;
            int reserve = 0;
            for (ATerPkg pkg : pkgList) {
                pkg.mno = mno;
                if (protocol instanceof WA206DeEnCoder) {
                    version = ((WA206Head) pkg.head).version;
                    reserve = ((WA206Head) pkg.head).reserve;
                }
            }
            TerTempData ter = TerGatewayMain.terEvnet.TerRecvPkg(connInfo.connId, mno, protocol.getProtocolName());
            ter.updateTerVerReve(version, reserve);
            // 开始处理业务消息
            for (ATerPkg pkg : pkgList) {
                TerGatewayMain.terEvnet.handleMsg(connInfo, pkg);
            }
        }
    }

    private static String getMno(List<ATerPkg> pkgList) {
        String mno = "";
        for (ATerPkg pkg : pkgList) {
            if (!StringUtil.IsNullOrEmpty(pkg.mno)) {
                mno = pkg.mno;
                break;
            }
        }
        return mno;
    }

    public static void main(String[] args) {
        byte[] pkgBytes = new byte[]{
                (byte)0xaa, (byte)0xaa, (byte)0x00, (byte)0x40, (byte)0x1d, (byte)0x86, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x62, (byte)0x0e, (byte)0x0f, (byte)0x03, (byte)0xe3, (byte)0x7b, (byte)0x2f, (byte)0xa0, (byte)0x91, (byte)0x3c, (byte)0x4f, (byte)0x2b, (byte)0xb3, (byte)0x60, (byte)0x82, (byte)0x9a, (byte)0xc9, (byte)0xd7, (byte)0xef, (byte)0x86, (byte)0x91, (byte)0x1a, (byte)0x08, (byte)0xc0, (byte)0xe5, (byte)0x3a, (byte)0xb1, (byte)0x91, (byte)0xc1, (byte)0x4b, (byte)0x6e, (byte)0xcd, (byte)0x23, (byte)0x85, (byte)0x29, (byte)0x68, (byte)0x37, (byte)0xca, (byte)0x3e, (byte)0x6b, (byte)0x7a, (byte)0x96, (byte)0xa6, (byte)0x78, (byte)0xd6, (byte)0xd5, (byte)0x2b, (byte)0x79, (byte)0xba, (byte)0x30, (byte)0x17, (byte)0x45, (byte)0x16, (byte)0x58
        };
        AProtocol protocol = new WA206DeEnCoder();//AutoProtocolImpl.getProtocol(WA206DeEnCoder.protocolName);
        if (null == protocol) {
            return;
        }
        // 如果是密文先尝试解密
        if (((pkgBytes[4] & 0xff) % 2) != 0) {
            // 取出密文报体
            byte[] bodyPkg = Arrays.copyOfRange(pkgBytes, WA206Head.HeadLen, pkgBytes.length - 2);
            // 解密报体
            bodyPkg = TbitTEAUtil.decrypt(bodyPkg, TbitTEAUtil.KEY);
            if (bodyPkg != null) {
                // 构造明文完整报文
                byte[] pkgs = new byte[WA206Head.HeadLen + bodyPkg.length + 2];
                System.arraycopy(pkgBytes, 0, pkgs, 0, WA206Head.HeadLen);
                // 重新设置长度，设置明文模式
                pkgs[2] = (byte) ((pkgs.length & 0xffff) >> 8);
                pkgs[3] = (byte) ((pkgs.length & 0xffff) >> 0);
                pkgs[4] = (byte) (pkgs[4] & 0xfe);
                System.arraycopy(bodyPkg, 0, pkgs, WA206Head.HeadLen, bodyPkg.length);
                // 重新计算校验和
                short crc = ProtocolUtil.GetCrcByteArray(pkgs, 2, pkgs.length - 4);
                pkgs[pkgs.length - 2] = (byte) ((crc & 0xffff) >> 8);
                pkgs[pkgs.length - 1] = (byte) ((crc & 0xffff) >> 0);
                pkgBytes = pkgs;
            }
        }
        // 取到设备编号生成设备唯一的mqtt连接对象
        String mno = StringUtil.TrimEnd(ByteUtil.BytesToHexString(pkgBytes, 10, 8), 'F');
        String connId = String.format("mqtt.%s", mno);
        AConnInfo connInfo = TerGatewayData.CheckMqttConnect(connId);
        if (null == connInfo) {
            return;
        }
        // 绑定协议
        connInfo.proName = protocol.getProtocolName();
        connInfo.mno = mno;
        // 封装成ByteBuf走协议解析和处理流程
        ByteBuf in = null;
        try {
            in = PooledByteBufAllocator.DEFAULT.directBuffer();
            in.writeBytes(pkgBytes);
            handlePkg(connInfo, protocol, in);
        } finally {
            if (null != in) {
                in.release();
                in = null;
            }
        }
    }
}
